﻿/************************************************************************
 * AIDE - Automata Identification Engine
 * Copyright (C) 2012-2013 Ali Khalili (khalili_DOT_ir_@SIGN_gmail_DOT_com)
 * **********************************************************************
 * This program is free software; you can redistribute it and/or modify it
 * under the terms of the GNU Lesser General Public License (LGPL) published 
 * by the Free Software Foundation; either version 2.1 of the License, or (at your
 * option) any later version. This program is distributed without any
 * warranty. See the GNU Lesser General Public License for more details. 
 * ***********************************************************************
 * File         :     AIDE\Oracles\DFAs\Oracle_MAT_DFA_Ideal.cs
 * Description  :     An ideal oracle for learning DFAs in MAT setting
 * Change log   :     -March 2013:  Initial version
 * To Do        :	 Move caching mechanism outside of oracle in filters
 ************************************************************************/

using System;
using System.Collections.Generic;
using SMLib.Automata.Base;
using SMLib.Automata.DFA;

namespace AIDE.Oracles.DFAs
{
    /// <summary>
    /// The Teacher/Oracle in the Angluin algorithm when the oracle knows the underlying machine
    /// </summary>
    public class Oracle_MAT_DFA_Ideal : IOracle_MAT_DFA
    {
        DFA SUT;
        public int numberOgMQ = 0, numberOfEQ = 0;

        //* Caching [IS WRONG!!!!]
        List<Word> acceptedWords, notAcceptedWords;
        bool useCaching;

        /// <summary>
        /// Constructor of the ideal oracle
        /// </summary>
        /// <param name="sut">The underlaying DFA</param>
        public Oracle_MAT_DFA_Ideal(DFA sut)
        {
            SUT = sut;
            acceptedWords = new List<Word>();
            notAcceptedWords = new List<Word>();
            useCaching = false;
        }

        /// <summary>
        /// Check whether a word is accepting or not
        /// </summary>
        /// <param name="a">The word to be checked</param>
        /// <returns>true, if accepting. false if not</returns>
        public bool MembershipQuery(Word a)
        {			
            if (useCaching)
            {
                foreach (Word w in acceptedWords)
                    if (w.Equals(a))
                        return true;

                foreach (Word w in notAcceptedWords)
                    if (w.Equals(a))
                        return false;
            }

            numberOgMQ++;
            DFA.DFA_State currentNode = (DFA.DFA_State)SUT.InitialState;
            for (int i = 0; i < a.Length; i++)
            {
                currentNode = currentNode.NextState(a[i]);
                if (currentNode == null)
                    return false;
            }

            if (useCaching)
            {
                if (currentNode.isAccepting)
                {
                    Word ac = new Word(a);
                    acceptedWords.Add(ac);
                }
                else
                {
                    Word nac = new Word(a);
                    notAcceptedWords.Add(nac);
                }
            }

            return currentNode.isAccepting;
        }


        /// <summary>
        /// Check equivalence (use the dfa equivalence checker)
        /// </summary>
        /// <param name="conjucture">the conjecture to be compared with</param>
        /// <returns>
        /// If null, the models are the same.
        /// if not, it is a counterexample which shows the models are not the same
        /// </returns>
        public Word EquivalenceQuery(DFA conjucture)
        {
            numberOfEQ++;
            DFA_EquivChecker eqCh = new DFA_EquivChecker();
            return eqCh.FindCounterexample(SUT, conjucture);
        }



        #region IOracle_MAT_DFA Members

        /// <summary>
        /// Input alphabet related to the DFA known by oracle
        /// </summary>
        public Alphabet inputAlphabet
        {
            get { return SUT.InputAlphabet; }
        }

        #endregion
    }
}
